#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

// volatile 保持内存可见性
// volatile int quit = 0;  

// void handler(int signo)
// {
//     printf("my pid : %d, signo : %d\n", getpid(), signo);
//     printf("%d", quit);
//     quit += 1;
//     printf(" -> %d\n", quit);
// }

// int main()
// {
//     signal(SIGINT, handler);
//     while(!quit);   // 这里不写任何操作，如果编译时加上“-O3”的选项，编译器就会帮我们做优化，quit的值就会被放入寄存器中
//     // 所以我们后续对quit的操作都是在内存中，cpu以后只会在那个寄存器上取值，所以它看不见内存了
// }


// 子进程退出时，是会给父进程发送17号信号的，父进程的默认动作是忽略
// 所以我们就可以在父进程对17号信号做自定义捕捉，然后在里面进行waitpid，这样就可以主动地等子进程退出了，不用阻塞等待了
// 但是注意，我们要循环等待，因为有可能在处理单一子进程时，其他子进程也在同一时刻退出，那么因为在处理信号函数时，收到同样的信号会被屏蔽
// 并且如果多个子进程同时退出也只会在pending位图上记录一次，这样就有可能造成子进程无人回收导致内存泄漏


void Count(int cnt)
{
    // 倒计时
    while(cnt)
    {
        printf("cnt : %2d\r", cnt--);
        fflush(stdout);
        sleep(1);
    }
    printf("\n");
}

void handler(int signo)
{
    printf("pid: %d, %d 号信号，正在被捕捉!\n", getpid(), signo);
}

int main()
{
    // 其实我们可以不等待子进程退出，并且子进程也不会僵尸，且自动被操作系统回收
    // 那就是显式对17号SIGCHLD进行忽略
    signal(SIGCHLD, SIG_IGN);
    signal(SIGCHLD, SIG_DFL);

    // 但是不对啊，刚刚不是说父进程收到17号信号的默认动作不就是忽略吗？
    // 注意，我们自己显式地设置和原先的默认动作还是不一样的


    printf("我是父进程, %d, ppid: %d\n", getpid(), getppid());
    // signal(17, handler);

    pid_t id = fork();
    if(id == 0)
    {
        printf("my pid : %d, my ppid : %d\n", getpid(), getppid());
        Count(10);
        exit(1);
    }
    while(1) sleep(1);
}




// #include <iostream>
// #include <cstdio>
// #include <signal.h>
// #include <unistd.h>
// void Count(int cnt)
// {
//     // 倒计时
//     while(cnt)
//     {
//         printf("cnt : %2d\r", cnt--);
//         fflush(stdout);
//         sleep(1);
//     }
//     cout << "\n";
// }

// void handler(int signo)
// {
//     cout << "\n" << signo << "号信号已递达！！！" << endl;
//     // sleep(10);
//     Count(20);
// }

// int main()
// {
//     // 今天使用一个新的信号捕捉函数 --- sigaction
//     struct sigaction act, oldact;

//     cout << "pid : " << getpid() << endl;

//     act.sa_handler = handler;   // 自定义处理动作
//     act.sa_flags = 0;

//     sigemptyset(&act.sa_mask);  // 初始化sa_mask，这个参数是用来设置当以后在处理信号函数中可以屏蔽的信号
//     sigaddset(&act.sa_mask, SIGQUIT);
//     // 当我们正在处理某一种信号的时候，我们也想顺便屏蔽其他信号，就可以添加到这个sa_mask中

//     sigaction(SIGINT, &act, &oldact);

//     while(1) sleep(1);

//     return 0;
// }